package hci;

import hci.utils.HciModifications;
import hci.utils.HciPersistence;
import hci.utils.MyPolygon;
import hci.utils.Session;

import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import javax.xml.parsers.ParserConfigurationException;


import org.xml.sax.SAXException;

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/**
 * Main class of the program - handles display of the main window
 * 
 * @author Michal
 * 
 */
public class ImageLabeller extends JFrame {
	/**
	 * some java stuff to get rid of warnings
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * main window panel
	 */
	JPanel appPanel = null;

	/**
	 * toolbox - put all buttons and stuff here!
	 */
	JPanel toolboxPanel = null;

	/**
	 * image panel - displays image and editing area
	 */
	ImagePanel imagePanel = null;

	JPanel imageContainer = null;

	JPanel messagePanel = null;

	public static JTextField messages = null;

	// Icons used, reference: http://openiconlibrary.sourceforge.net
	//	String openImageIconURL = new String("./icons/open.png");
	String saveIconURL = new String("./icons/save.png");
	String deletingIconURL = new String("./icons/delete.png");
	String openProjectIconURL = new String("./icons/openProject.png");
	String newFileIconURL = new String("./icons/new.png");
	String helpIconURL = new String("./icons/help.png");
	String labelsIconURL = new String("./icons/labels.png");
	String filename = new String();
	String filenameURL = new String();
	
	int NEWIMG = 1;
	int NEWPRO = 2;
	int OTHER = 0;

	boolean close = false;
	boolean closeProgram = false;
	static boolean viewLabels = false;
	boolean showingHelp = false;
	/** 
	 * handles New Object button action
	 */
	public void addNewPolygon() {
		HciModifications.setModifications(true);
		imagePanel.addNewPolygon();
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		imagePanel.paint(g); // update image panel
	}

	/**
	 * sets up application window
	 * 
	 * @param imageFilename
	 *            image to be loaded for editing
	 * @throws Exception
	 */
	public void setupGUI() {
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				// here we exit the program (maybe we should ask if the user
				// really wants to do it?)
				// maybe we also want to store the polygons somewhere? and read
				// them next time
				if(HciModifications.getModifications()){
					questionSave(true,OTHER);
					if(close){
						System.out.println("Bye bye!");
						System.exit(0);
					}
				} else {
					System.out.println("Bye bye!");
					System.exit(0);
				}
			}
		});

		// setup main window panel
		appPanel = new JPanel();
		this.setLayout(new BoxLayout(appPanel, BoxLayout.X_AXIS));
		this.setContentPane(appPanel);
		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		// Create and set up the image panel.
		// imagePanel = new ImagePanel(imageFilename);
		try {
			imagePanel = new ImagePanel("./images/U1003_0000.jpg");
		} catch (Exception e2) {
			// TODO Auto-generated catch block
			imagePanel = new ImagePanel();
		}
		imagePanel.setOpaque(true); // content panes must be opaque

		messagePanel = new JPanel();
		messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.Y_AXIS));

		messages = new JTextField();
		messages.setEditable(false);

		messagePanel.add(messages);
		messagePanel.setOpaque(true);
		imageContainer = new JPanel();
		imageContainer.add(imagePanel);

		messagePanel.add(imageContainer);
		messagePanel.add(messages);

		// Vertical Layout for the appPanel
		appPanel.setLayout(new BoxLayout(appPanel, BoxLayout.X_AXIS));

		// create toolbox panel
		toolboxPanel = new JPanel();
		toolboxPanel.setLayout(new BoxLayout(toolboxPanel, BoxLayout.Y_AXIS));


		// CREATE NEW PROJECT, OPEN IMAGE
		Icon newFileIcon = new ImageIcon(newFileIconURL);
		JButton newFileButton = new JButton(newFileIcon);
		newFileButton.setMnemonic(KeyEvent.VK_N);
		newFileButton
		.setSize(newFileIcon.getIconWidth(), newFileIcon.getIconHeight());
		newFileButton.setEnabled(true);
		newFileButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					if(HciModifications.getModifications()){
						questionSave(false,NEWIMG);
					} else {
						openNewImage();
					}
					//
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});

		newFileButton.setToolTipText("Click to create a new project form an image");

		// SAVE PROJECT
		Icon saveIcon = new ImageIcon(saveIconURL);
		JButton saveButton = new JButton(saveIcon);
		saveButton.setMnemonic(KeyEvent.VK_S);
		saveButton.setSize(saveIcon.getIconWidth(), saveIcon.getIconHeight());
		saveButton.setEnabled(true);
		saveButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					saveDocument(false,OTHER);
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});

		saveButton.setToolTipText("Click to save your project");

		// DELETE POLYGON
		Icon deletingIcon = new ImageIcon(deletingIconURL);
		final JButton deletingButton = new JButton(deletingIcon);
		deletingButton.setMnemonic(KeyEvent.VK_D);
		deletingButton.setSize(deletingIcon.getIconWidth(),
				deletingIcon.getIconHeight());
		deletingButton.setEnabled(true);
		deletingButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					deletingButton.getModel().setPressed(!deletingButton.getModel().isPressed());
					deletingMode();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});

		deletingButton.setToolTipText("Click start or stop deleting");

		// HELP
		Icon helpIcon = new ImageIcon(helpIconURL);
		final JButton helpButton = new JButton(helpIcon);
		helpButton.setMnemonic(KeyEvent.VK_H);
		helpButton.setSize(helpIcon.getIconWidth(),
				helpIcon.getIconHeight());
		helpButton.setEnabled(true);
		helpButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					help();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});

		helpButton.setToolTipText("Click to open the help");

		// OPEN PROJECT
		Icon openProjectIcon = new ImageIcon(openProjectIconURL);
		final JButton openProjectButton = new JButton(openProjectIcon);
		openProjectButton.setMnemonic(KeyEvent.VK_O);
		openProjectButton.setSize(openProjectIcon.getIconWidth(),
				openProjectIcon.getIconHeight());
		openProjectButton.setEnabled(true);
		openProjectButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					if(HciModifications.getModifications()){
						System.out.println("QUESTION SAVE");
						questionSave(false, NEWPRO);
					} else {
						System.out.println("OPEN DIRECT");
						openNewProject();
					}

				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});

		openProjectButton.setToolTipText("Click to open an existing project");

		// SHOW LABELS
		Icon labelsIcon = new ImageIcon(labelsIconURL);
		final JButton labelsButton = new JButton(labelsIcon);
		labelsButton.setMnemonic(KeyEvent.VK_H);
		labelsButton.setSize(labelsIcon.getIconWidth(),
				labelsIcon.getIconHeight());
		labelsButton.setEnabled(true);
		labelsButton.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					viewLabels();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		});

		labelsButton.setToolTipText("Click to view the labels");

		helpButton.setVisible(true);
		openProjectButton.setVisible(true);
		deletingButton.setVisible(true);
		newFileButton.setVisible(true);
		saveButton.setVisible(true);
		labelsButton.setVisible(true);

		toolboxPanel.setVisible(true);

		toolboxPanel.add(newFileButton);
		toolboxPanel.add(openProjectButton);
		toolboxPanel.add(saveButton);
		toolboxPanel.add(labelsButton);
		toolboxPanel.add(deletingButton);
		toolboxPanel.add(helpButton);
		toolboxPanel.add(Box.createVerticalGlue());


		appPanel.add(messagePanel);
		appPanel.add(toolboxPanel);

		// display all the stuff
		this.pack();
		this.setVisible(true);		
	}

	protected void viewLabels() {
		viewLabels = !viewLabels;
		if(viewLabels){
			messages.setText("Showing labels");
		} else {
			messages.setText("");
		}
		for (final MyPolygon p : imagePanel.polygonsList) {
			if(viewLabels){
				p.setShowingLabel(true);
			}else {
				p.setShowingLabel(false);	
			}
		}
		imagePanel.repaint();
	}


	protected void help() {
		if(showingHelp){
			messages.setText("Help is already opened");
		} else {
			messages.setText("Opening HELP ...");

			JEditorPane jep = new JEditorPane();
			jep.setEditable(false);

			JScrollPane jsp = new JScrollPane(jep);

			HTMLEditorKit kit = new HTMLEditorKit();
			jep.setEditorKit(kit);

			StyleSheet css = new StyleSheet();
			css.addRule("body {" +
					"color:#000000;" +
					"font-family:Times;" +
					"margin: 4px" +
					"font: 10px" +
			"}");
			css.addRule("h1 {" +
					"color:#0000FF;"+
					"font-family:Times;" +
					"margin:4px" +
					"font:12px bold;" +
			"}");

			String html = new String(	"<html style=\"background-color:yellow;\">" +
					"<body style=\"background-color:#FFFE73;\">" +
					"<h1>How to use this application?</h1> " +
					"Here you have the most frequent questions " +
					"about how you can use this image labelling application. " +
					"<h2>How to create a new project?</h2> " +
					"For creating a new project, just have to press " +
					"the first button with an image of a white sheet with a star " +
					"if you have made some modification at your project, will appear " +
					"a message for saving the project, after that, will appear the file chooser " +
					"where you can choose the image for start the new project. " +
					"<p>Image files that you can use: \"jpg\", \"jpeg\", \"png\", \"gif\". </p>" +
					"<h2>How to open a saved project?</h2> " +
					"To open a saved file, just have to click over the button with a folder icon, " +
					"then select the file that you would like to open and press \"Open\". " +
					"<h2>How to save the project?</h2> " +
					"To save the project, you have to press the button with the diskette icon " +
					"this is the third button, starting counting from the top. " +
					"You have to choose the location, enter the name for the file and press Save. " +
					"<h2>How to make a label?</h2> " +
					"If you would like to label a polygon, you only have to do double click " +
					"inside the desired polygon. Will appear a text field where you can " +
					"write the name of the label, when you have inserted the label name, press Enter. " +
					"If you would like to rename the label, you have to make double click inside the " +
					"desired polygon, and then you can rename the label. " +
					"<h2>How to view the labels?</h2> " +
					"There're two ways of viewing the labels: " +
					"<p>The first one is moving your mouse over one of the polygons, " +
					"will appear the name of the label of the polygon that you're over.</p> " +
					"<p>If you like to see all the labelled polygons, you can click at the fourth button " +
					"the one with an icon with a list of items. If you press this button, will appear over " +
					"all the polygons with her labels. To make them disappear, just click another time the same button.</p> " +
					"<h2>How to remove an existing polygon?</h2> " +
					"To remove an existing polygon you have to press the fifth button, the one with a litter. " +
					"The window will be surrounded with a red rectangle, this means that you are in the " +
					"delete mode, you only have to click over the polygon that you want to remove for deleting it. " +
					"When you have finished deleting polygons, press another time the same button " +
					"<h2>How to create a new polygon?</h2> " +
					"Just click over the image with a single click, will appear the new vertex created," +
					"when you have at less three vertexs, you can close the polygon making click over the " +
					"line that will appear between the first vertex added and the last one." +
					"<h2>How to drag a vertex?</h2>" +
					"Click over the vertex that you want to drag, and without leaving the left mouse button unpressed " +
					"drag the vertex to the desired position." +
					"<h2>How to drag a polygon?</h2> " +
					"Click inside the polygon that you want to drag, and with the left mouse button pressed " +
					"drag the polygon to the desired position. " +
					"<p><p> <b>Authors:</b> Adrià Navarro Martin, Albert Miró Amigó" + 
					"</body>" +
			"</html>");

			Document doc = kit.createDefaultDocument();
			jep.setDocument(doc);
			jep.setText(html);

			JFrame frame = new JFrame("Help");
			frame.getContentPane().add(jsp, BorderLayout.CENTER);
			frame.setDefaultCloseOperation(HIDE_ON_CLOSE);
			frame.addWindowListener(new WindowAdapter() {
				public void windowClosing(WindowEvent event) {
					showingHelp = false;
					messages.setText("");
				}
			});
			jep.setCaretPosition(0);
			frame.setSize(500,300);
			frame.setAlwaysOnTop(true);
			frame.setLocationRelativeTo(null);
			frame.setVisible(true);
			showingHelp = true;
		}
	}

	protected void questionSave(boolean exit, final int op) {

		final JFrame frame = new JFrame("Save");
		closeProgram = exit;
		final JPanel textPanel = new JPanel();
		textPanel.setLayout(new BoxLayout(textPanel,BoxLayout.Y_AXIS));
		frame.add(textPanel);

		final JPanel dialog = new JPanel();
		dialog.setLayout(new BoxLayout(dialog, BoxLayout.X_AXIS));

		frame.setUndecorated(false);
		final JLabel text = new JLabel("Do you want to save your document?");
		text.setVisible(true);
		text.setAlignmentX(CENTER_ALIGNMENT);
		JButton ok = new JButton("Save");
		ok.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				System.out.println("QS - OK");
				frame.setVisible(false);
				saveDocument(closeProgram,op);
				if(closeProgram){
					close = true;
					System.out.println("Bye, Bye");
					System.exit(0);
				}
			}


		});

		JButton cancel = new JButton("Cancel");
		cancel.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				close = true;
				frame.setVisible(false);
				if(closeProgram){
					System.out.println("Bye, Bye");
					System.exit(0);
				}
				if(op == NEWIMG){
					try {
						openNewImage();
					} catch (Exception e) {
						e.printStackTrace();
					}
				} else if (op == NEWPRO){
					System.out.println("QS - CANCEL");
					openNewProject();
				}
			}

		});


		frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

		textPanel.add(Box.createVerticalGlue());
		textPanel.add(text);
		textPanel.add(Box.createVerticalGlue());
		textPanel.add(dialog);

		dialog.add(Box.createHorizontalGlue());
		dialog.add(ok);
		dialog.add(Box.createHorizontalGlue());
		dialog.add(cancel);
		dialog.add(Box.createHorizontalGlue());
		textPanel.add(Box.createVerticalGlue());

		frame.setBounds(0, 0, 400, 100);
		frame.setVisible(true);

		frame.setAlwaysOnTop(true);
		frame.requestFocus();
		//To center the panel
		frame.setLocationRelativeTo(null);
	}

	protected void openNewProject() {

		JFileChooser chooser = new JFileChooser();

		FileNameExtensionFilter documentFilter = new FileNameExtensionFilter(
				"HCI Practical files", new String[] { "hci_practical" });
		chooser.addChoosableFileFilter(documentFilter);
		chooser.setFileFilter(documentFilter);
		chooser.setAcceptAllFileFilterUsed(false);

		int val = chooser.showOpenDialog(appPanel);
		if (val == chooser.APPROVE_OPTION) {
			File f = chooser.getSelectedFile();
			filename = f.getName();
			filenameURL = f.getAbsolutePath();
			System.out.println("OPEN NEW PROJECT");
			try {

				Session s = HciPersistence.restoreSession(f.getAbsolutePath());
				imagePanel.polygonsList = s.polygonsList;
				
				imagePanel.image = ImageIO.read(new File(s.imageFile));
				if (imagePanel.image.getWidth() > 800 || imagePanel.image.getHeight() > 600) {
					int newWidth = imagePanel.image.getWidth() > 800 ? 800
							: (imagePanel.image.getWidth() * 600) / imagePanel.image.getHeight();
					int newHeight = imagePanel.image.getHeight() > 600 ? 600
							: (imagePanel.image.getHeight() * 800) / imagePanel.image.getWidth();
					System.out.println("SCALING TO " + newWidth + "x" + newHeight);
					Image scaledImage = imagePanel.image.getScaledInstance(newWidth, newHeight,
							Image.SCALE_FAST);
					imagePanel.image = new BufferedImage(newWidth, newHeight,
							BufferedImage.TYPE_INT_RGB);
					imagePanel.image.getGraphics().drawImage(scaledImage, 0, 0, this);
				}
				
				imagePanel.repaint();
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			} catch (SAXException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			messages.setText("Opening New Project: "+filename);
		}

		
	}

	protected void deletingMode() {
		if(imagePanel.getDeleltingMode() == "ON"){
			messages.setText("Deleting Mode: ON");
		} else {
			messages.setText("");
		}
		imagePanel.deletingMode();
	}

	protected void saveDocument(boolean exit,final int op) {
		if(filename.isEmpty()){
			System.out.println("EMPTY");
			
			
			JFileChooser chooser = new JFileChooser();

			int val = chooser.showSaveDialog(appPanel);
			if (val == chooser.APPROVE_OPTION) {
				filename = chooser.getSelectedFile().getName()+".hci_practical";
				filenameURL = chooser.getSelectedFile().getAbsolutePath()+".hci_practical";
				imagePanel.saveFile(filenameURL);
				messages.setText("SAVED: "+filename);
				close = exit;
				HciModifications.setModifications(false);
				repaint();
				if(op == NEWPRO){
					System.out.println("QS OK - NAME SAVE");
					openNewProject();
				} else if (op == NEWIMG){
					try {
						openNewImage();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					if(closeProgram){
						messages.setText("Bye, Bye");
						System.exit(0);
					}
				}
			} else if(val == chooser.CANCEL_OPTION) {
				//TODO 
				if(op == NEWPRO){
					openNewProject();
				} else if (op == NEWIMG){
					try {
						openNewImage();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					if(closeProgram){
						System.out.println("Bye, Bye");
						System.exit(0);
					}
				}
				if(closeProgram){
					System.out.println("Bye, Bye");
					System.exit(0);
				}
			}
		} else {
			System.out.println("NO EMPTY");
			messages.setText("SAVED: "+filename);
			imagePanel.saveFile(filenameURL);
			close = exit;
			if(op == NEWPRO){
				openNewProject();
			} else if (op == NEWIMG){
				try {
					openNewImage();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				if(closeProgram){
					System.out.println("Bye, Bye");
					System.exit(0);
				}
			}
		}
		return;
	}

	
	protected void openNewImage() throws Exception {
		JFileChooser chooser = new JFileChooser();

		FileNameExtensionFilter imageFilter = new FileNameExtensionFilter(
				"Images files", new String[] { "jpg", "jpeg", "png", "gif"});
		chooser.addChoosableFileFilter(imageFilter);
		chooser.setFileFilter(imageFilter);
		chooser.setAcceptAllFileFilterUsed(false);
		int val = chooser.showOpenDialog(appPanel);
		if (val == chooser.APPROVE_OPTION) {
			File f = chooser.getSelectedFile();
			System.out.println("File: " + f.getName());
			// Create and set up the image panel.
			
			imageContainer.remove(imagePanel);
			imagePanel = new ImagePanel(f.getAbsolutePath());
			imagePanel.setOpaque(true);
			imageContainer.add(imagePanel);
			this.pack();
			this.setVisible(true);
			messages.setText("OPENED: "+f.getName());
			filename = "";
			filenameURL = "";
		}

	}

	/**
	 * Runs the program
	 * 
	 * @param argv
	 *            path to an image
	 */
	public static void main(String argv[]) {

		// create a window and display the image
			ImageLabeller window = new ImageLabeller();
			HciModifications.setModifications(false);
			window.setResizable(false);
			window.setupGUI();
	}
}
